/*                           Software License Agreement
;
; The software supplied herewith by Microchip Technology Incorporated (the "Company")
; for its PICmicro Microcontroller is intended and supplied to you, the Companys
; customer, for use solely and exclusively on Microchip PICmicro Microcontroller
; products.
;
; The software is owned by the Company and/or its supplier, and is protected under
; applicable copyright laws. All rights are reserved. Any use in violation of the
; foregoing restrictions may subject the user to criminal sanctions under applicable
; laws, as well as to civil liability for the breach of the terms and conditions of
; this license.
;
; THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, WHETHER EXPRESS,
; IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE
; COMPANY SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
; CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
;
; ###############################################################################
;	filename:		Pres_Pal.C
;				
; This file implements a device coined the "Presentation Pal."  The Presentation 
; Pal receives an RF transmission from a transmitter implemented on the rfPIC(tm)
; for the purpose of assisting a slide show presentation.  The transmitter 
; consists of two buttons: one for advancing a slide and the other for going back 
; a slide.  The receiver portion (this file) enumerates as a keyboard and 
; essentially sends key presses to the host.  For advancing a slide a PgDn is 
; sent, and for going back a slide a PgUp is sent.  When both buttons on the 
; transmitter are pressed, Alt-Tab is sent so the other applications can be
; selected.  In this mode the Button 1 on the transmitter moves the selector to
; the desired application icon and Button 2 selects it.  The receiver then 
; returns to a mode were Button 1 and 2 either advance or go back a slide.  
;
; ###############################################################################
;
;	Authors:		Reston Condit
;	Company:		Microchip Technology Inc
;
;	Revision:		-
;	Date:			07 January 2002
;	Assembled using		MPLAB 5.20 / HI-TECH C 7.86 PL2
;	Configuration Bits:	H4 Oscillator, WDT Off, Power up timer off
; 	Revision History:
;
;################################################################################*/

//	include files:

#include <pic.h>
#include "usb.h"

/*################################################################################*/

__CONFIG(0x3F3A);  // H4 Oscillator, WDT Off, Power up timer off, Code Protect off

unsigned int TMR1 @ 0x0E;
unsigned char BUFFER[8];
unsigned int SERIAL_NO3;
unsigned char MAIN_STATE;
unsigned int COUNTER;
unsigned int STORED_CNTR;
unsigned char DELAY;
bit LRN; 	// 0 = no device learned; 1 = device learned
bit BUTTON1; 	// 1 = Button 1 pushed
bit BUTTON2; 	// 1 = Button 2 pushed
	
// Code word receive routine.
unsigned char Receive() {                                                                           
	unsigned char STATE;
	unsigned char BIT_CNTR;
	unsigned int HIGH_PULSE_WIDTH;
	unsigned int LOW_PULSE_WIDTH;
	unsigned int CODE_WORDS;
	CODE_WORDS = 0;
	BIT_CNTR = 0;
	STATE = 1;
	RBIF = 0; 		// clear interrupt flag
	TMR1 = 0;
	TMR1IF = 0;
	while (STATE != 0)
	{
		switch (STATE) 
		{
			case 1:		// wait for RB7 to go low; if greater that 500us seconds exit
			{
				if (!RB7) {
					STATE += 1;
					TMR1 = 0;
				}
				if (TMR1 >= 3000)
					STATE = 0;
				break;
			}
			case 2:		// wait for RB7 to be low 3 ms
			{
				if (TMR1 >= 18000)		// 3 ms
					STATE += 1;
				
				if (RB7)
					STATE = 0;
				break;
			}
			case 3:		// if low pulse length between 3 ms and 5 ms then proceed else 
						//   receive fails and interrupt is exited 
			{
				if (RB7) {
					STATE += 1;
					TMR1 = 0;
					TMR1IF = 0;
				}
				else if (TMR1 >= 30000)	// 5 ms
					STATE = 0;
				break;
			}
			case 4:   // time length of high pulse; repeated 16 times
			{
				if (!RB7) {
					STATE += 1;
					HIGH_PULSE_WIDTH = TMR1;
					TMR1 = 0;
					TMR1IF = 0;
					if (HIGH_PULSE_WIDTH < 1800) { // if length too short then exit
						STATE = 0;
					}
				}
				if (TMR1 > 6000)	// if length too long then exit
					STATE = 0;
				break;
			}
			case 5:   // time length of low pulse; repeated 16 times
			{
				if (RB7) {
					STATE += 1;
					LOW_PULSE_WIDTH = TMR1;
					TMR1 = 0;
					TMR1IF = 0;
					if (LOW_PULSE_WIDTH < 1800) { // if length too short then exit
						STATE = 0;
					}
				}
				if (TMR1IF > 6000)	// if length too long then exit
					STATE = 0;	
				break;
			}
			case 6:   // determine code bit and move into CODE_WORDS
			{
				BIT_CNTR++;
				if (HIGH_PULSE_WIDTH < LOW_PULSE_WIDTH) {
					if (BIT_CNTR >= 16)
						COUNTER |= 0x8000;
					else
						CODE_WORDS |= 0x8000;
				}
				if (BIT_CNTR >= 32) {
				    STATE += 1;
					TMR1 = 0;
					TMR1IF = 0;
				}
				else {
					if (BIT_CNTR >= 16)
						COUNTER >>= 1;
					else {
						CODE_WORDS >>= 1;
					}
					STATE = 4;
				}
				break;
			}
			case 7:   // check serial number
			{
				if (LRN == 0) {  // if no device has been learned, learn this one 
					SERIAL_NO3 = (CODE_WORDS & 0x03FF);
					LRN = 1;
				}
				if ((CODE_WORDS & 0x03FF) == SERIAL_NO3)
					STATE += 1;
				else
					STATE = 0;  // if serial number doesn't match then exit
				break;
			}
			case 8:   // read function bits											
			{
				STATE = 0;
				if ((CODE_WORDS & 0x2000) == 0x2000) { 
					BUTTON1 = 1;
					MAIN_STATE += 1;
					RB1 = 1;
					RB2 = 0;
				}
				if ((CODE_WORDS & 0x4000) == 0x4000) {
					BUTTON2 = 1;
					MAIN_STATE += 1;
					RB2 = 1;
					RB1 = 0;
				}
				DELAY = 0;
				TMR0 = 0;					
				T0IF = 0;
				T0IE = 1;
				break;
			}
		}
	}
	return;
}

// Interrupt service routine. Branch off to different interrupts.
interrupt ISR () {
	if (USBIF && USBIE)
		ServiceUSBInt();
	if (T0IF && T0IE) {
		if (DELAY++ > 40) {
			RB1 = 0;
			RB2 = 0;
			T0IE = 0;
		}
		T0IF = 0;
	}
}

void InitRegisters() {
	TRISB = 0x80; 		// RB0-RB6 -> output; RB7 -> input
	PORTB = 0;
	LRN = 0;
	BUTTON1 = 0;
	BUTTON2 = 0;
	SERIAL_NO3 = 0;
	BUFFER[0] = 0;
	BUFFER[1] = 0;
	BUFFER[2] = 0;
	BUFFER[3] = 0;
	BUFFER[4] = 0;
	BUFFER[5] = 0;
	BUFFER[6] = 0;
	BUFFER[7] = 0;
	COUNTER = 0;
	STORED_CNTR = 0;
	T1CON =	0x01;		// turn Timer1 on; no prescaler 
	TMR1IF = 1;
	TMR1IE = 0;
	RBIE = 0;
	OPTION = 0x87;		// pull-ups disabled, TMR0 prescaler = 1:256
	MAIN_STATE = 0;
	return;
}

void main() {
	unsigned char i;
	unsigned char PAUSE;
	InitRegisters(); 		// initialize non-usb registers
	for (i = 0; i < 50; i ++);  	// wait before initializing USB
	InitUSB();			// initialize USB
	while ((USWSTAT & 0x03) != 3);  // wait here until configured 
	RB0 = 1;
	PAUSE = 0;
	while(1) {
		switch (MAIN_STATE)
		{
			case 0:		// wait to receive transmission
			{
				if (RBIF) {
					Receive();
				}
				break;
			}
			case 1:
			{
				if (COUNTER == STORED_CNTR) {
					if (PAUSE < 8) {
						MAIN_STATE -= 1;
						BUTTON1 = 0;
						BUTTON2 = 0;
						PAUSE += 1;
					}
					else {
						MAIN_STATE += 1;
					}	
				}
				else {
					PAUSE = 0;
					STORED_CNTR = COUNTER;
					MAIN_STATE += 1;
				}
				break;
			}
			case 2:		// send keyboard pageup or pagedown command
			{
				if (BUTTON1) {
					BUFFER[2] = 75;  // pageup
					BUTTON1 = 0;
				}
				if (BUTTON2) {
					BUFFER[2] = 78;  // pagedown
					BUTTON2 = 0;
				}
				while (PutEP1(8, BUFFER) == 0);
				TMR1 = 0;
				TMR1IF = 0;
				MAIN_STATE += 1;
				break;
			}
			case 3:		// clear paging command
			{
				if (TMR1IF) {
					TMR1IF = 0;
					BUFFER[2] = 0;
					while (PutEP1(8, BUFFER) == 0);
					MAIN_STATE = 0;
				}
				break;
			}
		}
	}
}

